﻿//using Microsoft.VisualStudio.OLE.Interop;
using SolidEdgeAssembly;
using SolidEdgeFramework;
using SolidEdgePart;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using Microsoft.VisualStudio.OLE.Interop;
//using Microsoft.WindowsAPICodePack.Shell;
//using DemoTG.res;

namespace DemoTG
{
    [Flags]
    public enum STGM
    {
        DIRECT = 0x00000000,
        TRANSACTED = 0x00010000,
        SIMPLE = 0x08000000,
        READ = 0x00000000,
        WRITE = 0x00000001,
        READWRITE = 0x00000002,
        SHARE_DENY_NONE = 0x00000040,
        SHARE_DENY_READ = 0x00000030,
        SHARE_DENY_WRITE = 0x00000020,
        SHARE_EXCLUSIVE = 0x00000010,
        PRIORITY = 0x00040000,
        DELETEONRELEASE = 0x04000000,
        NOSCRATCH = 0x00100000,
        CREATE = 0x00001000,
        CONVERT = 0x00020000,
        FAILIFTHERE = 0x00000000,
        NOSNAPSHOT = 0x00200000,
        DIRECT_SWMR = 0x00400000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public int iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    }

    public class NDSNexInterface
    {
        /// <summary>
        /// SolidEdge Application
        /// </summary>
        private static SolidEdgeFramework.Application _application = null;

        private static string _version = null;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="application"></param>
        /// <returns></returns>
        public static bool Initialize(SolidEdgeFramework.Application application)
        {

            _application = application;

            return false;
        }

        /// <summary>
        /// 获取版本
        /// </summary>
        /// <returns></returns>
        public static string GetApplicationVersion()
        {
            if (_version != null)
                return _version;

            if (_application == null)
                return "";

            string caption = _application.Caption;
            _version = caption.Substring(caption.Length - 4);
            return _version;
        }

        /// <summary>
        /// 获取窗口句柄
        /// </summary>
        /// <returns></returns>
        public static IntPtr GetApplicationWindowHandle()
        {
            if (_application == null)
                return IntPtr.Zero;

            return new IntPtr(_application.hWnd);
        }

        /// <summary>
        /// 获取当前激活的文档
        /// </summary>
        /// <returns></returns>
        public static SolidEdgeDocument GetCurrentDocument()
        {
            if(_application == null)
            {
                //LogInstance.WriteLog("获取当前激活文档失败，未成功获取当前实例");
                return null;
            }
            try
            {
                return (SolidEdgeDocument)_application.ActiveDocument;
            }
            catch (System.Exception ex)
            {
               // LogInstance.WriteLog("获取当前激活文档异常：" + ex.Message);
                return null;
            }        
        }

        /// <summary>
        /// 根据文件全路径获取当前已经打开的Document对象
        /// </summary>
        /// <param name="fullPath">文件全路径</param>
        /// <returns>已经打开的Document对象，没有打开时返回null</returns>
        public static SolidEdgeDocument GetOpenedDocument(string fullPath)
        {
            if(_application == null)
            {
                return null;
            }
            Documents openedDocs = _application.Documents;
            foreach (SolidEdgeDocument doc in _application.Documents)
            {
                if (doc.FullName == fullPath)
                    return doc;
            }
            return null;
        }

        /// <summary>
        /// 设置当前激活文件
        /// </summary>
        /// <param name="fullpath"></param>
        /// <returns></returns>
        public static bool SetActiveDocument(string fullpath)
        {
            var document = GetOpenedDocument(fullpath);
            if (document != null)
            {
                document.Activate();
                return true;
            }

            return false;
        }


        /// <summary>
        /// 获取文档当前配置
        /// </summary>
        /// <param name="document">SE文档</param>
        /// <returns>当前配置名</returns>
        public static string GetDocumentCurrentConfig(SolidEdgeDocument document)
        {
            string configName = "";
            switch (document.Type)
            {
                case SolidEdgeFramework.DocumentTypeConstants.igAssemblyDocument:
                    {
                        AssemblyDocument asmDoc = (AssemblyDocument)document;
                        configName = asmDoc.ActiveConfiguration;
                        break;
                    }
                case SolidEdgeFramework.DocumentTypeConstants.igPartDocument:
                    {
                        PartDocument partDoc = (PartDocument)document;
                        FamilyMembers partFamliys = partDoc.FamilyMembers;
                        configName = System.IO.Path.GetFileNameWithoutExtension(partDoc.FullName);
                        break;
                    }
                case SolidEdgeFramework.DocumentTypeConstants.igSheetMetalDocument:
                    break;
                default:
                    break;
            }

            return configName;
        }

        /// <summary>
        /// 判断文档是否打开
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool IsDocumentOpened(string filePath)
        {
            var document = GetOpenedDocument(filePath);
            if (document != null)
                return true;

            return false;
        }

        /// <summary>
        /// 打开文件
        /// </summary>
        /// <param name="filepth">文件路径</param>
        /// <param name="bSilent">隐藏的方式打开</param>
        /// <returns></returns>
        public static SolidEdgeDocument OpenDocument(string filepth, bool bSilent = false)
        {
            if (_application == null)
                return null;

            try
            {
                if (bSilent)
                    return _application.Documents.Open(filepth, 8) as SolidEdgeDocument;
                else
                    return _application.Documents.Open(filepth) as SolidEdgeDocument;
            }
            catch (System.Exception ex)
            {
               // LogInstance.WriteLog("打开文档异常：" + ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 关闭文档
        /// </summary>
        /// <param name="document"></param>
        public static void CloseDocument(SolidEdgeDocument document)
        {
            try
            {
                document.Close();
            }
            catch (System.Exception ex)
            {
                //LogInstance.WriteLog("关闭文档异常：" + ex.Message);
            }         
        }

        /// <summary>
        /// 保存文档
        /// </summary>
        /// <param name="document"></param>
        public static bool SaveDocument(SolidEdgeDocument document)
        {
            if (document == null)
                return false;

            try
            {
                if(document.ReadOnly == false)
                    document.Save();
            }
            catch (System.Exception ex)
            {
                //LogInstance.WriteLog("关闭文档异常：" + ex.Message);
            }

            return true;
        }

        /// <summary>
        /// 判断文件是否修改为保存
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        public static bool IsDocumentModified(SolidEdgeDocument document)
        {
            if (document == null)
                return false;

            return document.Dirty;
        }

        public static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
        /// <summary>
        /// 保存文档至PDF
        /// </summary>
        /// <param name="document"></param>
        /// <param name="saveDirectory"></param>
        /// <returns></returns>
        public static string SaveDocAsPDF(SolidEdgeDocument document, string saveDirectory)
        {
            bool docReadOnly = false;
            bool bAfterSetReadOnly = false;
            string docName = document.Name;
            string fileName = System.IO.Path.GetFileNameWithoutExtension(docName);
            string pdfFullPath = saveDirectory + "\\" + fileName + ".pdf";
            try
            {          
                if (File.Exists(pdfFullPath))
                {
                    File.Delete(pdfFullPath);
                }

                if (document.Type != SolidEdgeFramework.DocumentTypeConstants.igDraftDocument)
                {
                    if(IsHavingBodyInDoc(document) == false)
                    {
                        return "";
                    }
                }

                docReadOnly = document.ReadOnly;
                if (docReadOnly)
                    document.ReadOnly = false;  // this operation may cause exception

                bAfterSetReadOnly = true;
                if (document.Type == SolidEdgeFramework.DocumentTypeConstants.igDraftDocument)
                {//save as 2D PDF
                    document.SaveAs(pdfFullPath, null, false);
                }
                else
                {//save as 3D PDF
               
                    document.SaveAs(pdfFullPath, null, true);               
                }

                document.ReadOnly = docReadOnly;
                return pdfFullPath;

            }
            catch (System.Exception ex)
            {
                if (docReadOnly && bAfterSetReadOnly == false)
                { //if current document can't export pdf, copy a file to reopen and save as pdf
                    SolidEdgeDocument openDoc = null;
                    string tmpFilePath = "";
                    string tmpConfigPath = "";
                    try
                    {
                        string path = document.FullName;
                        
                        string dir = document.Path;
                        string ext = System.IO.Path.GetExtension(path);
                        ext = ext.ToLower();
                        string time = GetTimeStamp();
                        tmpFilePath = dir + "\\" + fileName + "_" + time + ext;
                        if(ext == ".asm")
                        {
                            tmpConfigPath = dir + "\\" + fileName + "_" + time + ".cfg";
                        }
                        File.Copy(path, tmpFilePath, true);
                        if (File.Exists(tmpFilePath))
                        {
                            NDSHelper.SetFileReadOnly(tmpFilePath, false);

                            openDoc = OpenDocument(tmpFilePath, true);
                            if(openDoc != null)
                            {
                                if (openDoc.Type == SolidEdgeFramework.DocumentTypeConstants.igDraftDocument)
                                {//save as 2D PDF
                                    openDoc.SaveAs(pdfFullPath, null, false);
                                }
                                else
                                {//save as 3D PDF

                                    openDoc.SaveAs(pdfFullPath, null, true);
                                }
                                openDoc.Close();
                                File.Delete(tmpFilePath);
                                if (tmpConfigPath != "" && File.Exists(tmpConfigPath)) //delete the assembly's cfg file automatically generated by Nex3D
                                    File.Delete(tmpConfigPath);
                                
                                return pdfFullPath;
                            }

                            File.Delete(tmpFilePath);
                            if (tmpConfigPath != "" && File.Exists(tmpConfigPath))
                                File.Delete(tmpConfigPath);
                        }
                        
                    }
                    catch (System.Exception ex2)
                    {
                        if (openDoc != null)
                            openDoc.Close();
                        if(tmpFilePath != "" && File.Exists(tmpFilePath))
                            File.Delete(tmpFilePath);

                        if (tmpConfigPath != "" && File.Exists(tmpConfigPath))
                            File.Delete(tmpConfigPath);

                        //LogInstance.WriteLog("另存为PDF异常：" + ex2.Message);
                        return "";
                    }                                      
                   
                }
                else
                {

                  //  LogInstance.WriteLog("另存为PDF异常：" + ex.Message);
                }
                return "";
            }
            
        }

        public static bool  IsHavingBodyInDoc(SolidEdgeDocument document)
        {
            if (document.Type == SolidEdgeFramework.DocumentTypeConstants.igPartDocument)
            {
                PartDocument partDoc = (PartDocument)document;
                Models models = partDoc.Models;
                Constructions constructions = partDoc.Constructions;

                int count1 = models.Count;
                int count2 = constructions.Count;
                if (count1 > 0 || count2 > 0)
                    return true;
                else
                    return false;
            }
            else if (document.Type == SolidEdgeFramework.DocumentTypeConstants.igSheetMetalDocument)
            {
                SheetMetalDocument sheetMetalDoc = (SheetMetalDocument)document;
                Models models = sheetMetalDoc.Models;
                Constructions constructions = sheetMetalDoc.Constructions;
                int count1 = models.Count;
                int count2 = constructions.Count;
                if (count1 > 0 || count2 > 0)
                    return true;
                else
                    return false;
            }
            else if (document.Type == SolidEdgeFramework.DocumentTypeConstants.igAssemblyDocument)
            {
                AssemblyDocument assemDoc = (AssemblyDocument)document;
                AssemblyBodies assemBodies = assemDoc.AssemblyBodies;
                Constructions constructions = assemDoc.Constructions;
                int count1 = assemBodies.Count;
                int count2 = constructions.Count;
                if (count1 > 0 || count2 > 0)
                    return true;

                int occurNum = assemDoc.Occurrences.Count;
                foreach (Occurrence occur in assemDoc.Occurrences)
                {
                    SolidEdgeDocument occuDoc = (SolidEdgeDocument)occur.OccurrenceDocument;
                    bool bHasBody = IsHavingBodyInDoc(occuDoc);
                    if (bHasBody)
                        return true;
                }
                return false;
            }
            else
            {
                return false;
            }

        }

        #region Memory Stream Methods


        /// <summary>
        /// 写String数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <param name="value"></param>
        public static void WriteStringToStream(MemoryStream pStream, string value)
        {
            if (value.Length > 0)
            {
                byte[] byteData = Encoding.Default.GetBytes(value);
                //write string length
                WriteIntToStream(pStream, byteData.Length);
                //write string data
                pStream.Write(byteData, 0, byteData.Length);
            }
            else
            {
                WriteIntToStream(pStream, 0);
            }
        }

        /// <summary>
        /// 读取String数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <returns></returns>
        public static string ReadStringFromStream(MemoryStream pStream)
        {
            int strLen = ReadIntFromStream(pStream);
            if (strLen > 0)
            {
                byte[] byteData = new byte[strLen];
                pStream.Read(byteData, 0, strLen);
                return Encoding.Default.GetString(byteData, 0, strLen);
            }
            else
            {
                return "";
            }
        }

        /// <summary>
        /// 写int数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <param name="value"></param>
        public static void WriteIntToStream(MemoryStream pStream, int value)
        {
            byte[] byteData = System.BitConverter.GetBytes(value);
            pStream.Write(byteData, 0, byteData.Length);
        }



        /// <summary>
        /// 读取int数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <returns></returns>
        public static int ReadIntFromStream(MemoryStream pStream)
        {
            int intSize = sizeof(int);
            byte[] byteData = new byte[intSize];
            pStream.Read(byteData, 0, intSize);

            return System.BitConverter.ToInt32(byteData, 0);
        }

        /// <summary>
        /// 写bool数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <param name="value"></param>
        public static void WriteBooleanToStream(MemoryStream pStream, bool value)
        {
            byte[] byteData = System.BitConverter.GetBytes(value);
            pStream.Write(byteData, 0, sizeof(bool));
        }

        /// <summary>
        /// 读bool数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <returns></returns>
        public static bool ReadBooleanFromStream(MemoryStream pStream)
        {
            int boolSize = sizeof(bool);
            byte[] byteData = new byte[boolSize];
            pStream.Read(byteData, 0, boolSize);

            return System.BitConverter.ToBoolean(byteData, 0);
        }

        /// <summary>
        /// 写double数据
        /// </summary>
        /// <param name="pStream"></param>
        /// <param name="value"></param>
        public static void WriteDoubleToStream(MemoryStream pStream, double value)
        {
            byte[] byteData = System.BitConverter.GetBytes(value);
            pStream.Write(byteData, 0, byteData.Length);
        }

        public static double ReadDoubleFromStream(MemoryStream pStream)
        {
            int doubleSize = sizeof(double);
            byte[] byteData = new byte[doubleSize];
            pStream.Read(byteData, 0, doubleSize);

            return System.BitConverter.ToDouble(byteData, 0);
        }
        #endregion
    }
}
